#pragma once

#include <stdint.h>
#include <sys/epoll.h>
#include <functional>

class EventLoop;
class Channel
{
private:
    EventLoop *_loop;  // 当前文件描述符属于哪一个EventLoop对象
    int _fd;           // 当前管理的文件描述符
    uint32_t _events;  // 当前fd需要关心的事件
    uint32_t _revents; // 当前fd就绪的事件
    using EventCallback = std::function<void()>;

    EventCallback _read_callback;
    EventCallback _write_callback;
    EventCallback _error_callback;
    EventCallback _close_callback;
    EventCallback _event_callback;

public:
    Channel(EventLoop *loop, int fd);

    // 1. 获取当前fd
    int Fd();

    // 2. 获取当前fd关心的事件
    uint32_t Events();

    // 3. 设置就绪事件
    void SetREvents(uint32_t events);

    // 4. 向Channel对象注册各类事件的处理函数
    void SetReadCallback(const EventCallback &cb);
    void SetWriteCallback(const EventCallback &cb);
    void SetCloseCallback(const EventCallback &cb);
    void SetErrorCallback(const EventCallback &cb);
    void SetEventCallback(const EventCallback &cb);

    // 5. 当前是否监控可读事件
    bool ReadAble();

    // 6. 当前是否监控可写事件
    bool WriteAble();

    // 7. 启动可读事件监控
    void EnableRead();

    // 8. 启动可写事件监控
    void EnableWrite();

    // 9. 关闭读事件监控
    void DisableRead();

    // 10. 关闭写事件监控
    void DisableWrite();

    // 11. 关闭所有事件监控
    void DisableAll();

    /*
        关闭事件监控，只是不去关心这个事件了，但还是在EventLoop中。
        移除事件监控，才是真正的将它从EventLoop中移除
    */
    // 12. 移除监控
    void Remove();

    // 13. 更新事件监控
    void Updata();

    /*
        EventLoop不管你触发了什么事件我就去调用对应的回调函数，EventLoop不用管。
        EventLoop只管你触发了事件，我就调用你的HandleEvent，你自己来决定什么样的事件该如何处理
        这是最能体现Channel模块作用的功能之一
    */
    // 14. 事件处理，一旦连接触发了事件，就调用这个函数，自己触发了什么事件如何处理自己决定
    void HandleEvent();
};